��������������������������������������������������������������������������������������
�                                                                                    �
�                        [x] ringZ3r0  Proudly Presents [x]                          �
�                                                                                    �
�           ������������������������������������������������������������             �
�                                                                                    �
                � PE-Packers/Crypters : Manual unpacking - parte 1 �

                                     Kill3xx

                                  10 Giugno,1999

--==[  PREMESSA  ]==-----------------------------------------------------------------

LE INFORMAZIONI CHE TROVATE ALL'INTERNO DI QUESTO FILE SONO PER PURO SCOPO DIDATTICO.
L'AUTORE NON INCORAGGIA CHI VOLESSE UTILIZZARLE PER SCOPI ILLEGALI.

--==[ DIFFICOLTA' ]==----------------------------------------------------------------

scala : *=Novizio, **=Apprendista, ***=Esperto, ****=Guru
target: **1/2 ***

--==[ TOOLS USATI ]==----------------------------------------------------------------
 
* SoftIce 3.25
* ADUMP 1.0
* MAKEPE 1.30
* PE Browse
* HIEW 6.14
* ULTRAEDIT 6.10
* MASM 6.14

--==[ LETTERATURA ]==----------------------------------------------------------------

"Peering Inside the PE: A Tour of the Win32 Portable Executable File Format" 
(M. Pietrek),  Microsoft Systems Journal 3/1994

"Windows 95 Programming Secrets" (M. Pietrek), IDG BOOKS, 1995

"Window Advanced Programming" (J. Ritcher), Microsoft Press, 1997

"Why to Use _declspec(dllimport) & _declspec(dllexport) In Code", MS KB Q132044

"Writing Multiple-Language Resources", MS Knowledge Base Q89866

"The Portable Executable File Format from Top to Bottom" (Randy Kath), MSDN

"The PE file format" (B. Luevelsmeyer), reperibile sulla rete

--==[ INTRODUZIONE ]==--------------------------------------------------------------

Un saluto a tutti,
come avrete constatato e' passato parecchio tempo dal mio ultimo tutorial ma causa 
lavoro e studio (hey ho una vita "reale" anche io ;) non ho avuto molto tempo per 
dedicarmi a scrivere le mie stupidaggini (che poi sono pure lunghe ;)
Comunque come vi avevo promesso l'ultima volta eccomi di nuovo sull'argomento PE:
in questo secondo capitolo della saga ;) cercheremo di sviscerare quello che si cela
dietro l'oscura tecnica (o arte ;) del "manual unpacking". In tutto questo tempo ho
potuto constatare che l'interesse intorno al PE e alle sue piu' o meno spinte 
manipolazioni ha incontrato un grosso successo di pubblico; 
sara' per via che i programmi sono sempre piu' spesso compressi o criptati, sara'
perche' ci si e' resi conto che la conoscenza della struttura degli eseguibili win32
consente approcci nuovi al R.E. (leggi code iniection, process pacthing,api hooking,
ecc.) ma noto che c'e' un crescente numero di persone che si  interessano di PE.
Prima di incominciare pero' e' necessaria una piccola premessa: in questo secondo 
tutorial la conoscenza di base delle strutture del PE e' data per scontata per cui 
nel caso non le abbiate chiare vi consiglio di leggere prima i testi in letteratura
o il mio precedente tutorial (pubblicita' occulta ;), altra cosa.. e' anche necessaria
una conoscenza di base sul funzionamento di alcuni dei meccanismi a basso livello 
del nostro adorato WinSlow (context,address spaces, MMF,ecc.) per cui non sara' una 
lettura propriamente leggera =)

Ok.. Let's go...

--==[ NOZIONI GENERALI ]==----------------------------------------------------------

Il PE unpacking e' una tecnica relativamente giovane che pero' ha gia' una sua
storia:
certamente chi di voi frequenta il sito di +Fravia ricordera' i tutorial di Jazz,
Quine, HalVar e quelli ormai famosi di Marigold su VBOX, ecc. e ricordera' anche che
l'approccio seguito (battezzato da Marigold stesso "virginity restoring") altro non 
era che un'operazione di manual unpacking. L'idea di fondo e' molto semplice in se':
per quanto possa essere complessa l'encryption del target, di una cosa siamo sicuri,
se il programma deve poter essere eseguito,in memoria dobbiamo _necessariamente_ 
avere un'immagine "in chiaro" del codice/dati/risorse...
detto questo e' naturale la conclusione: se possiamo salvare su disco le varie parti
del codice, dei dati,ecc. e ricostruire la struttura del PE avremo un eseguibile 
perfettamente funzionante ,patchabile e/o dissasemblabile. Certo dalle parole ai 
fatti ci passa parecchio: innanzitutto sappiamo bene che alcune strutture del PE sono 
modificate durante la creazione di un processo (la IAT, la posizione delle section,
ecc.) e che lo stesso codice/dati possono essere alterati (relocation.. cosa 
tristemente vera per le DLL), pero' sappiamo anche quando ed in base a quali regole 
questa alterazione avviene. Un'altro problema e' la separazione degli address spaces:
secondo i dettami win32 ogni processo a 32bit possiede  un suo proprio spazio di 
indirizzamento virtuale e non puo' accere a quello di un'altro processo: 
come possiamo allora leggere e salvare il contenuto delle section dell'eseguibile 
se non conosciamo il mapping delle pagine che utilizza e soprattutto non possiamo 
accerdevi? 
La risposta e' che la premessa e' falsa, nel senso che la separazione dei processi 
non e' assoluta, o meglio, e' aggirabile in svariati modi, anche semplici 
(affermazione questa che dipende molto dal S.O. .. i.e. w9x != Nt 4.x,5):
il primo che ci viene in mente e' quello di utilizzare del codice a ring0 che abbia
accesso alla GDT,alla/e LDT, alle page tables/directory o cmq alle strutture 
utilizzate dal Memory Manager (VMM) e dal kernel (VWIN32) per creare i context: 
hey chi di voi ha detto SoftIce ? =) 
esatto i debugger di sistema come SoftIce, w386dbg o TRW devono necessariamente
avere conoscenza dei context e degli address spaces per poter funzionare. E' poi
possibile accedere alla memoria di un'altro processo anche da ring3 utilizzando 
api dedicate ai debuggers come ReadProcessMemory,GetThreadContext,SetThreadContext 
(questa e' ad exp la strada seguita da ProcDump).
Un'altro sistema potrebbe essere quello di iniettare (utilizzanto system hooks o
altri sistemi) del nostro codice (una DLL o un MMF) nel processo target e 
condividere in tal modo il suo stesso memory context (e' il sistema che ho scelto 
di usare nei sorgenti del PE-Spy allegato a questo tutorial).
Procediamo con ordine: il metodo del system debugger (SoftIce su tutti) per dumpare
l'image dell'eseguibile e' quella piu' usata e flessibile, perche' ci permette al 
contempo di seguire a runtime le operazioni che il nostro target compie e di avere
un controllo preciso sul context e sull'uso della memoria dello stesso. 
Comandi come map32, addr, pagein (SoftIce) sono un prezioso aiuto per il nostro 
compito e ci facilitano non poco la vita. L'unico problema e' dove salvare le aree
che ci interessano: la risposta piu' ovvia sarebbe su un file.. ma come sappiamo non
e' possibile aprire un file in un context (ad exp un nostro programma di dumping) ed 
utilizzarlo in un'altro perche' gli handle sono opachi rispetto ai processi; anche 
un rep movsb verso un buffer da noi allocato non sortirebbe effetto migliore per via
della separazione dei context... un bel guaio... una soluzione potrebbe essere
creare a runtime ,direttamente in SoftIce,  uno snippet di codice che apra il file e
usi WriteFile.. ma e' una bella seccatura assemblare il tutto a mano..
la soluzione sta nei Memory Mapped File: come sappiamo questi sono aree shared (in
w9x allocate nell'arena > 80000000 < c0000000) e visibili in tutti i processi 
(in NT a patto di chiamare esplicitamente OpenFileMapping + MapViewOfFile) quindi 
possiamo usare un MMF per far comunicare il nostro target (via SoftIce) e il dumper.. 
ci bastera' usare il comando m (=move) e copiare i dati sul MMF e poi semplicemente 
salvare il contenuto di questo su file dal dumper stesso.
Questo all'incirca e'  il principio di funzionamento della maggior parte dei dumper
(SofDump,ADUMP,ecc.). Essi creano un MMF ci ritornano un address valido al blocco
shared, che poi noi possiamo utilizzare come indirizzo destinazione nel comando m. 
Una variante a questo metodo ce la offre Icedump che e' una vera e propria
patch di SoftIce: utilizzando lo spazio di codice "superfluo", Icedump aggiunge la 
possibilita' di salvare in un file direttamente da SoftIce. Ancora piu' semplice
e' l'uso di TRW che include  una serie di comandi per il dump su disco dell'image
di un modulo PE (mkPE, PEDUMP). I vantaggi di questi approcci sono che abbiamo
un controllo completo della vittima (possiamo steppare, esaminare il codice, i
registri, ecc..) e possimo decidere con maggiore precisione quando agire e salvare 
il contenuto della mem su disco. Lo svantaggio e' che la maggior parte del lavoro 
(cut&pasting, rebuild della IT, del pe header, bla bla) e' a carico nostro almeno 
se escludiamo TRW. 
Se decidiamo di non usare questi debuggers l'alternativa e' sostanzialmente Procdump.
Giunto alla versione 1.4, Procdump ci permette di salvare su file ogni singola 
sezione dell'eseguibile, l'immagine intera o un blocco parziale. Per fare questo 
Procdump utilizza l'api toolhelp32/psapi e quella per i dbgs per esaminare il PE 
header cosi' come mappato a runtime, leggere il contenuto delle sections in un 
buffer locale (in entrambi i casi attraverso ReadProcessMemory) e quindi salvarlo
su file.. non male  =)
Benche' il tutto avvenga restando a ring3 il processo di dump e' efficace ed in piu'
automatizzato, specialmente per quel che riguarda il rebuild della IT, e dell'header.
Procdump offre inoltre una modalita' trace a r3 e/o r0 che affiancata ad un sistema 
di scripting lo rende molto flessibile. Gli svantaggi sono soprattutto legati 
all'implementazione stessa.. usando l'api di debug a r3.. procdump e' molto piu'
limitato nel controllo dell'esecuzione (il thread hopping gli fa molto male =),
ma soprattuto e' detectabile (fs:20,IsDebuggerPresent, test sul TF, ecc.).
Un'ultima soluzione e' quella di creare del codice che una volta iniettato nel 
processo target poi funzioni da "server" di dumping e salvi il contenuto delle
aree che ci interessano su disco. La cosa si ottine abbastanza semplicemente 
utilizzando i system hooks (SetWindowHookEx,ecc., ad exp. msg hooks) o altri
sistemi di code iniection e quindi creando una window che funga da server ed esegua 
direttamente nell'address space della vittima le operazioni di dumping,ecc. che 
intendiamo compiere.Il vantaggio e' che condividiamo lo stesso context della vittima
e che quindi nessun address da questo raggiungibile ci e' precluso. Gli svantaggi:
beh siamo sempre a r3 e non abbiamo controllo se non parziale sull'esecuzione del
processo. Ok, credo che questa parte disgustosamente teorica vi abbia gia' stancato..
ma come dico sempre la cosa migliore e' conoscere bene il nemico e le armi che 
abbiamo a disposizione.. non vorrete mika abbattere un f16 con una fionda ? =)


--==[ MANUAL UNPACKING ]==----------------------------------------------------------

Dopo la doverosa parentesi maniaco-tecnika =) proviamo ad entrare nel vivo del 
discorso esaminando passo passo una sessione di unpacking.
Come primo target utilizzeremo un programma criptato col PESentry: se qualcuno
sta gia' mormorando: hey perche' proprio il PESentry e non qualkosa di piu'
complesso tipo PE-Shield,PE-Crypt,ecc.. semplice di PESentry ne ho gia' ampiamente 
spiegato il funzionamento nel precedente tutorial e per di piu' potete fare 
riferimento anche i sorgenti.. i principi del manual unpacking sono gli stessi quale
che sia il target tanto vale spiegarli usando un esempio chiaro per tutti.
Come lavoro preliminare quindi utilizzate su un target il PESentry.. chesso' il 
buon vecchio notepad (io lo uso sempre quando studio i vari packers/crypters =)
detto fatto.. ora abbiamo un bel eseguibile cryptato: 
la prima operazione che faccio quando approccio un target packed e studiarmi
il PE header e le strutture connesse cosi' come appaiono su disco.. e' 
un'operazione fondamentale perche' ci consente di capire parecchie cose sul 
potenziale funzionamento del packer. Lanciate allora PeBrowse (o per i nostalgici 
della CUI,il PEDUMP) e cominciate ad esaminare l'header.. prima di tutto diamo 
un'okkiata all' Optional Header e alla section table:

ImageBase    = 0x00400000                 SectionAlign = 0x00001000
BaseOfcode   = 0x00001000                 EntryPoint   = 0x0000BA04
BaseOfData   = 0x00005000                 ImageSize    = 0x0000D000

Section Table
  01 .text     VirtSize: 00003953  VirtAddr:  00001000
    raw data offs:   00000400  raw data size: 00003A00
    characteristics: E0000020
      CODE  MEM_EXECUTE  MEM_READ  MEM_WRITE
  02 .bss      VirtSize: 0000043A  VirtAddr:  00005000
    raw data offs:   00000000  raw data size: 00000000
    characteristics: C0000080
      UNINITIALIZED_DATA  MEM_READ  MEM_WRITE
  03 .data     VirtSize: 00000212  VirtAddr:  00006000
    raw data offs:   00003E00  raw data size: 00000400
    characteristics: C0000040
      INITIALIZED_DATA  MEM_READ  MEM_WRITE
  04 .idata    VirtSize: 00000C9A  VirtAddr:  00007000
    raw data offs:   00004200  raw data size: 00000E00
    characteristics: C0000040
      INITIALIZED_DATA  MEM_READ  MEM_WRITE
  05 .rsrc     VirtSize: 00003000  VirtAddr:  00008000
    raw data offs:   00005000  raw data size: 00002E00
    characteristics: C0000040
      INITIALIZED_DATA  MEM_READ  MEM_WRITE
  06 .reloc    VirtSize: 00002000  VirtAddr:  0000B000
    raw data offs:   00007E00  raw data size: 00001600
    characteristics: E0000040
      INITIALIZED_DATA  MEM_EXECUTE  MEM_READ  MEM_WRITE

umm.. non ci vuol molto a vedere che qualcosa non quadra =)
l'EP e' spostato ad un RVA = BA04 proprio dentro la .reloc che presenta tra l'altro
i flags executable ed writable, quest'ultimo attivo anche per ogni altra section
(questo fatto e' una classica green light.. ricordate che in genere i packers 
gestiscono manualmente la base relocation, non e' pensabile usare WriteProcessMemory
per applicare i fixups, mentre e' possibile che ne incontriate alcuni che utilizzano 
VirtualProtect per alterare runtime le protezioni di pagina). L'ImageSize sembra 
invece corretta, come del resto la coerenza tra RawSize,VirtualSize e VirtualAddress:
quest'ultima considerazione e' molto importante perche' ci consente di distinguere
in genere un packer da un crypter: a meno che il loader non sia particolarmente 
sofisticato lo spazio per il mapping delle sezioni verra' riservato cmq attraverso i
valori VirtualSize e VirtualAddress specificati nell'header.. quindi se trovate una
RawSize molto piu' piccola rispetto al dovuto, o addirittura nulla, ma una VirtualSize
correttamente allineata con l'inizio della section seguente..beh con ogni probabilita'
avete a che fare con un packer. Continuiamo esaminando le varie data directories:

  EXPORT       rva: 00000000  size: 00000000
  IMPORT       rva: 0000BD66  size: 00000C9A
  RESOURCE     rva: 00008000  size: 00002CE0
  BASERELOC    rva: 0000BDDA  size: 0000000A
  TLS          rva: 00000000  size: 00000000
  BOUND_IMPORT rva: 00000000  size: 00000000
  IAT          rva: 00000000  size: 00000000

dunque dunque.. nessuna funct esportata (normale di x gli .exe), niente TLS, bound 
imports, umm.. una base reloc con size 0x0A.. sospetto..  una import table che punta 
ancora una volta all'interno della .reloc.. molto molto sospetto! =)
esaminiamo la IT:

Imports Table:
  KERNEL32.DLL
  Hint/Name Table: 0000BD9B
  First thunk RVA: 0000BDA7
  Ordn  Name
     0  GetProcAddress (IAT: 0000BDB3)
     0  GetModuleHandleA (IAT: 0000BDC4)

solo due imports .. eheh una vocina mi dice che e' implementato un imports loader e
che il loader gestisce anche la base relocation (dato che non e' probabile che le 
relocation siano stripped non essendo specificato nel FileHeader ed essendoci una
sect .reloc di una certa dimensione... chiamatelo zen... o meglio chiamateli 
sorgenti =)
Se esaminiamo con PeBrowse le risorse ci accorgiamo subito che:
1) la sezione che la contiene non e' completamente criptata dato che i nodi che 
costituisco la res directory sono integri
2) le singole risorse invece sono criptate ad esclusione delle icone

Vabbeh.. ci siamo fatti un quadro della situazione.. ora e' il momento di procedere
ad analizzare il loader a runtime...riassumiamo i nostri obbiettivi:

1) salvare le sezioni decrittate
2) cercare e salvare la IT originale (eventualmente ricostruirla se distrutta)
3) cercare e salvare la RELOC originale (eventualmente ricostruirla se distrutta)
   strettamente necessario solo per le DLL,DRV,ecc.
4) salvare le risorse decrittate
5) trovare l'EP originale
7) assemblare le sezioni salvate in un unico file
8) ricostuire un PE header coerente (ImageSize,EP,Section Headers,ecc.)

piccola tips.. ora volendo utilizzare sIce saremmo tentati di lanciare il programma 
con symbol loader.. in genere e' preferibile evitarlo cosi' non dobbiamo
preoccuparci di check su fs:20 o cmq sul PDB (process database) che alcuni packer
fanno per evitare process patchers o unpackers alla procdump... sara' sufficente
sostituire il primo byte all'EP con 0xCC (=int3, con hiew l'operazione e' 
velocissima: load; F4 decode; F8 header; F5 entrypoint; F3 modify; F9 save ) 
e mettere un bpint 3.. quando lanceremo il programma avremo immediatamente il 
controllo.. quindi E EIP oldbyte, e continuiamo allegramente a steppare nel codice
del loader. Per quel che riguarda TRW nelle ultime versioni (>0.72) include un nuovo
comando TRnewTCB, che hookando services r0 per la gestione dei threads 
(VMMCreateThread -> Call_When_Thread_Switched) consente di breckare nell'entrypoint
del main thread dell'applicazione. Ora la fase successiva e' comprendere cosa sta 
facendo il loader ed attenderlo al varco, ovvero quando ha finito di decrittare, e
quindi procedere al dump delle singole sezioni. Per il dump utilizzeremo ADUMP 
(Icedump 4 se avete una ver < 3.24). Lanciamo quindi ADUMP e digitiamo R per avere
le informazioni sul MMF creato by default:

   STARTOFFS: 0x82E23000
     ENDOFFS: 0x82F17240
       LIMIT: 0xF4240    (1000000 )
     CUROFFS: 0x82E23000
       MAPFN: C:\WINDOWS\TEMP\ADump.log
    MAPFSIZE: 0xF4240
    ANFILTER: A..Z,a..z,0..9

ok.. la dimensione di base (limit) e' sufficiente considerata l'imagesize del 
nostro target; lo start address e' 0x82E23000.. lanciamo notepad.exe.. 
SoftIce poppa... sezione notepad!.reloc... ok... diamo un'occhiata all'header: 
map32 notepad ... ok come da copione.. continuiamo.. nella code window sIce 
abbiamo ora l'entrypoint del decryptor di PESentry.. chiaramente a questo
punto dovremmo steppare nel codice e tentare di capire cosa accade ma dato
che abbiamo i sorgenti commentati questa volta possiamo rilassarci e dedicarci 
solo ad alcune considerazioni generali.La mia idea e' di analizzare le azioni
compiute da PESentry ed isolare dei patterns che possano essere applicati
per la comprensione di ogni altro packers/crypters. Proviamo a riassumere il 
comportamento di PESentry in termini di patterns piu' o meno atomici:

1) setup/inizializzazione decryptor
 1a) salvataggio dei flags / registri
 1b) calcolo del delta -> imagebase
 1c) installazione di un exception handler : questa va considerata una red light.. 
     l'exception handler puo' essere usato solo per trappare eventuali errori 
     ma puo' anche essere indice di codice antidebug che usi ad esempio nested 
     exceptions + context->eip context->flags->tf, le varie interfaccie int3 di 
     sIce, ecc.. fate quindi sempre attenzione al codice dell'xHandler. 
 1d) inizializzazione pseudo IAT : e' evidente che il loader ha bisogno di
     utilizzare delle api di WinZoZ, quindi operazione preliminare e' ottenere
     gli addresses di queste: tipicamente si possono presentare due casi:
     
     a) il loader importa tutte le funzioni necessarie nella sua IT
     b) il loader importa solo GetModuleHandleA,GetProcAddress,LoadLibrary
        e inizializza runtime una IAT interna. Questo e' il caso di PESentry,
        Ci puo' essere un'ulteriore complicazione: seguendo il codice di 
        PESentry non troviamo nessuna call a GetProcAddress.. uhm, davvero 
        strano.. come fa ad importare le funzioni? esaminando il codice ci 
        accorgiamo che utilizza un export scanner: in pratica invece che 
        utilizzare GetProcAddress, una volta ottenuto l'hModule emula 
        GetProcAddress percorrendo la ExportTable->AddressOfNames e/o 
        ExportTable->AddressOfFunction (nel caso sia importato  by ordinal)
2) decryptor loop : tipicamente questo e' table driven, ovvero utilizza una
   table/struc che gli fornisce le informazioni su dove e cosa decrittare.. 
   ad exp. PeSentry il loop do PESentry procede dalla prima sezione (0x1000)
   e prosegue fino all'ultima (0xB000) 
 2a) handling separato delle strutture del PE (reloc, res,ecc.): nel caso
   di notepad abbiamo ad exp un blocco "if RVA=0x8000 then" che dall'analisi 
   preventiva sappiamo essere le resourse directory
3) binding della IAT originale del programma. Anche qui possono presentarsi due 
   casi:
   a) l'imports handler utilizza l'IT originale una volta decrittata (tipicamente
      la sezione .idata)
   b) l'imports handler possiede copia interna compressa/criptata distruttuta
      una volta utilizzata
   anche nel caso del binding della IAT originale si applicano le osservazioni
   del punto 1d)
4) applicazione dei fixup se current imagebase != preferred imagebase
5) deallocazione risorse/memoria utilizzate / ripristino registri / stack  
6) jmp host_original_entrypoint: qui le varianti non si contano... dal classico
   jmp eax a pop EP_addr..ret e via discorrendo
     
nel caso di PESentry al termine del decryption loop e' lecito attendersi la seguente 
situazione:

1) le sezioni codice e dati sono decrittate
2) la sezione .rsrc  e' stata decrittata
3) la sezione .idata e' stata decrittata
4) non sono ancora stati applicati i fixups (base relocation)
5) la IAT non e' stata ancora patchata

supponendo di non avere i sorgenti se esaminaste da SIce la sezione .idata e .reloc 
avreste cmq la conferma delle nostre supposizioni dato che sia le informazioni
per i vari image_imports_descriptor che le informazioni di rilocazione sono presenti 
in chiaro.. se ne dedurrebbe quindi  che il loader utilizza la IT e la RELOC 
originali.. cmq avere la IAT non patchata ci evita il problema di dover ricostuire 
manualmente i vari image_thunk_data mentre il fatto che che non sia ancora 
intervenuta nessuna rilocazione (altamente improbabile negli eseguibili, vista la
separazione degli address spaces, ma cmq possibile nell'eventualita' che il loader 
rilochi maliziosamente l'image per rendere inutile ad exp. il full dump di ProcDump
o TRW) ci garantisce che codice e dati statici sono nel loro stato originario.
Ad ogni modo questo e' indubbiamente il momento migliore per salvare l'immagine
delle sezioni, per cui da SoftIce digitiamo:

:map32 notepad
:m 401000 L 3a00 82e23000
:m 405000 L 1000 82e27000
:m 406000 L 1000 82e29000
:m 405000 L 3000 82e2b000
:m 40b000 L 2000 82e2f000

ovvero  m sect_start_addr L sect_virtualsize(aligned) MMF_dest_addr
nel caso le pagine interessate non siano ancora presenti dovrete forzare il MM di 
WinSlow a caricarle con pagein (se utilizzate Icedump non avrete di questi problemi)..
naturalmente avremmo anche potuto fare il dump dell'intera immagine e poi rimuovere 
la sezione .BSS ma siccome questo tutorial lo sto scrivendo io vediamo di non 
rompere le ... ;)).. a questo punto l'unica informazione che ci manca e' l'entrypoint
originale.. non ci resta che steppare in sice finche' incontriamo il fatidico
jmp eax che riporta l'esecuzione al EP originale di notepad..  EP = 0x401000...
next step...uscite da sIce e digitate in ADUMP:

:w c:\working\text_dump.bin 3a00 82e23000
Data written (14848) bytes.
:w c:\working\data_dump.bin 1000 82e27000
Data written (4096) bytes.
:w c:\working\idata_dump.bin 1000 82e29000
Data written (4096) bytes.
:w c:\working\rsrc_dump.bin 3000 82e2b000
Data written (12288) bytes.
:w c:\working\reloc_dump.bin 2000 82e2f000
Data written (8192) bytes.

ed avrete una copia dell'immagine decrittata...well done... pero' per ripristinare
l'eseguibile e' necessario innanzitutto ricostruire l'header:
in genere utilizzo un header "vergine" che mi son fatto allo scopo.. ma potete anche 
usare quello del target stesso. Cmq vogliate procedere quello che ci aspetta ora e'
un bel lavoretto di taglio e cucito =) quindi aprite ultraedit o il vostro hex editor
di fiducia ed  inserite l'header: il mio ha size 400h essendo gia' allineato 
(hey "vedo che il tuo sforzo e' grosso come il mio" nd MelBrooks =) quindi a seguire
tutti i file che contengono le sezioni:

ofs 0x400  -> text_dump.bin
ofs 0x3e00 -> reloc_dump.bin
ofs 0x4200 -> idata_dump.bin
ofs 0x5000 -> rsrc_dump.bin
ofs 0x7e00 -> reloc_dump.bin

come vedete l'offset a cui vengono inseriti e' allineato al file align (minimo 200h 
ma se volete ottimizzare i caricamenti in w98 o nt = 1000h).. inoltre nel caso 
probabile che il dump sia piu'lungo dei dati reali (exp la .reloc contiene ancora il 
codice del decryptor) potete ovviamente ridurli, dato che comunque lo spazio non 
presente su disco verra' allocato a load time da winZoz cosi' come specificato nei 
section headers. Fatto questo dobbiamo rendere coerente l'header almeno nelle sue 
parti fondamentali:

NumberOfSection = 6
ImageBase       = 0x400000 
Section Align   = 0x1000
File Align      = 0x200  (opzionale 0x1000)
ImageSize       = 0xC000 (allineata section align x compatibilita' con NT)
EntryPoint      = 0x1000 (rva)

una nota a margine merita il discorso PE CRC.. questo campo andrebbe aggiornato
corretamnte solo nel caso abbiate a che fare con eseguibili potenzialmete 
utilizzabili in NT come processi di sistema (services,ecc.) in quanto il loader 
di NT ne verifica la correttezza. Per calcolare il CRC avete a disposizione
svariati metodi: potete utilizzare le funzioni deputate a questo scopo dalla
stessa M$ nel modulo IMAGEHLP.DLL.. utilizzare un programma di ricalcolo
del crc (quello di Rudeboy/PC va benissimo e sono disponibili anche i srcs), 
o lo stesso linker del MASM (switch -RELEASE).

quindi dobbiamo inserire i 6 section headers : .text, .data, .bss (questa ha
come ovvio RawSize=0, VirtualSize=0x1000), .idata, .rsrc, .reloc (vi ricordo 
che sono consecutivi a partire dalla fine dell'OptionalHeader)... segue
per questioni di spazio la dichiarazione della sola .text :

IMAGE_SECTION_HEADER STRUCT DWORD
    Name                   8 dup(?)     | 2E54455854000000  | .TEXT
    VirtualSize               dd ?      | 003A0000          | 00003A00
    VirtualAddress            dd ?      | 00100000          | 00001000
    SizeOfRawData             dd ?      | 003A0000          | 00003A00
    PointerToRawData          dd ?      | 00040000          | 00000400
    PointerToRelocations      dd ?      | 00000000          | 00000000
    PointerToLinenumbers      dd ?      | 00000000          | 00000000
    NumberOfRelocations	      dw ?      |     0000          |     0000
    NumberOfLinenumbers	      dw ?      |     0000          |     0000
    Characteristics           dd ?      | 20000060          | CODE+EXECUTE+READ
IMAGE_SECTION_HEADER ENDS
  
come vedete ho ripristinato i flags in modo coerente (writable = off) ma questa e' 
generalmente solo un'operazione di cosmesi e non influisce sul funzionamento
(salvo il programma avesse gia' di suo il flag writable in questo caso ve ne 
accorgereste subito ;) . 
Ora resta da aggiornare la datadir in modo che riporti correttamente le entry piu' 
importanti:

------------------------------------------------  
*  IMPORT       rva: 00007000  size: 00000CA0  *
------------------------------------------------

l'import directory e' indubbiamente quella che ci crea piu' grattacapi essendo una 
struttura one-shot: infatti sappiamo che una volta che il loader ha patchato la IAT,
la IT (di cui la IAT e' parte ma che non necessariamente risiede nelle stessa section)
diventa inutile. E' quindi evidente che a runtime questa entry non e' necessariamente
corretta, anzi lo e' di rado nei packers piu' recenti. Tuttavia la IT e' solo il
mezzo non lo scopo, mi spiego meglio: come sappiamo quello che e' vitale per il 
programma non e' la IT ma proprio la IAT.. questa deve assolutamente trovarsi nella 
posizione originaria altrimenti le jmp/call [dword] con cui il linker ha risolto le 
chiamate alle funzioni importate non potranno funzionare. Nessuno ci vieta di spostare
la IT (intesa come image_import_descritors) o di crearne una nuova, purche' i vari 
First_Thunks puntino ai corrispondenti nella IAT originale. Consideriamo ora PESentry:
la IT utilizzata e' quella originaria che viene solamente criptata ma che cmq conserva
inalterata la sua stuttura, sappiamo inoltre che se interveniamo prima della 
call HandleImports, la IAT e' i rispettivi image_thunk_data sono perfettamente 
integri.. e' dunque chiaro che l'entry IMPORT dovra' semplicemente puntare all'RVA 
a cui runtime troviamo l'inizio della IT (x  notepad.exe RVA = 0x7000 = .idata)
dato che i valori RVA negli array FirstThunk sono gia' corretti. Quanto alla size 
essa corrisponde alla dimensione fisica dei dati = 0x4ea0 - 0x4200 = 0x0ca0.
Ora immagino qualcuno stara' pensando: "ma se la IT non si trova in una section 
separata come faccio ad identificarla e sopratutto a stabilirne le dimensioni ?"
La risposta e' semplice: o seguite l'esecuzione fino trovare la funzione che parsa
la IT (che solitamente presenta dei pattern di facile identificazione.. guardatevi
il codice di HandleImports in PESentry) oppure ricercate in memoria le stringhe
dei moduli/api (ad exp. S -CU 400000 L d000 "kernel32.dll") e percorrete a ritroso
la struttura della IT (su qesto argomento parlero' piu' in dettaglio tra un attimo).
Tuttavia quello di PESEntry e' uno dei casi piu' favorevoli.. come comportarsi allora
nel caso il packer utilizzi per il binding un copia "usa e getta" (compressa e/o 
criptata) della IT? Anche in questo caso una possibile soluzione e' cercare di
identificare le funzioni che si occupano del binding della IAT e verificare se e'
possibile ottenerne una copia valida della IT. Ma supponiamo che il precedente 
tentativo sia fallito..non restebbe che ricostruire la IT a mano.. sappiamo solo 
che la IAT e' stata fixata, non conosciamo ne la sua posizione ne le sue dimensioni:
immagino stiate dicendo: "cosa??? r u crazy?!" =).. eheh in realta' e' possibile 
utilizzare MKPE di GROM/UCF, che implementa lo stesso algoritmo di rebuild del 
procdump ma su base "statica".. qui invece ci interessa trattare proprio dell'estrema
 ratio.. il rebuild manuale della IT. Innanzitutto cominciamo col trovare la IAT:

0137:00401007  FF1548734000        CALL    [KERNEL32!GetCommandLineA]

sappiamo che il linker risolve le imports come jmp/call [DWORD]..l'address 0x407348 
corrisponde dunque all' image_thunk_data x GetCommandLineA all'interno della IAT.
Ora col l'ausilio della grafica =)) cerchiamo di analizzare la IAT cosi' come
ci apparirebbe in sIce:

0137:00407000 00007160  2A504F7F  FFFFFFFF  000074E8      `q..OP*.....t..
              |         |         |         |       
              |     +-------------+         |
              | +---------------------------+
              | |   |   |
              | |   |   |   IMAGE_IMPORT_DESCRIPTOR    STRUC
              +-|---|-----> OrigFirstThunk        DD    ?
                |   |   +-> TimeDateStamp         DD    ?
                |   +-----> ForwarderChain        DD    ?
                +---------> NameRVA               DD    ?   
              +-----------> FirstThunk            DD    ?
              |            IMAGE_IMPORT_DESCRIPTOR     ENDS
              |
0137:00407010 00007370  000070D0  320C1CA0  FFFFFFFF      ps...p.....2....
.... omissis ....
0137:00407060 0000747C |00000000  00000000  00000000      |t..............
0137:00407070 00000000  00000000  00007C0A  00007BF8      .........|...{..
                               |  |
modules descriptors terminator-+  +-start SHELL32 OriginalThunk
.... omissis ....
0137:004070C0 00007BBA  00007B2C  00007BE4  00000000      .{..,{...{......
                                            ^^^^^^^^
0137:004070D0 000075F6  000075EA  000075DA  00007604      .u...u...u...v..
.... omissis ....
0137:00407150 00007640  0000764A  00007654  00000000      @v..Jv..Tv......
                                            ^^^^^^^^
0137:00407160 000074D8  000074B4  000074A6  000074C6      .t...t...t...t..
.... omissis ....
0137:00407250 0000770E  000076FC  000076EE  00007812      .w...v...v...x..
0137:00407280 00007C20  00000000  BFF32CF0  BFF324A7       |.......,...$..
                               |  |       
Terminator COMDLG32 OriginThunk+  +-start SHELL32 FirstThunk
0137:00407290 BFF3215A  BFF34517  BFF32497  BFF324AB      Z!...E...$...$..
.... omissis ....
0137:004072C0 BFF324E7  BFF3227E  BFF31882  BFF31C1D      .$..~"..........
0137:004072D0 BFF324FB  BFF324AF  BFF31C11  00000000      .$...$..........
                                            |       
             Terminator SHELL32 FirstThunk -+
0137:004072E0 BFF74904  BFF9CE2C  BFF76E13  BFF77395      .I..,....n...s..
.... omissis ....
0137:00407340 BFF82941  BFF7799C  BFF89F65  BFF7FB33      A)...y..e...3...
                                  |       
-- we land here ----------------> +- GetCommandLineA 
0137:00407350 BFF76DF1  BFF8AECD  BFF77654  BFF775BD      .m......Tv...u..
0137:00407360 BFF9CDBE  BFF773FB  BFF77425  00000000      .....s..%t......
                                            |       
            Terminator KERNEL32 FirstThunk -+
0137:00407370 7FDD8F0E  7FDC2B22  7FDD71DD  7FDC1220      ..."+..q. ..
0137:00407380 7FE0B03C  00000000  BFF64CBD  BFF64D7C      <.......L..|M..
0137:00407390 BFF61718  BFF6406A  BFF62B96  BFF62B48      ....j@...+..H+..
.... omissis ....
0137:00407470 BFF64CE9  BFF61508  00000000  7FE84F95      .L...........O.
0137:00407480 7FE868A8  7FE85768  7FE81162  7FE84FA3      .h.hW.b...O.
0137:00407490 7FE8609C  00000000  6853004C  416C6C65      .`.....L.ShellA
                        |       
                        +- Terminator COMDLG32 FirstThunk
0137:004074A0 74756F62  00090041  67617244  696E6946      boutA...DragFini
0137:004074B0 00006873  7244000B  75516761  46797265      sh....DragQueryF
0137:004074C0 41656C69  00080000  67617244  65636341      ileA....DragAcce
0137:004074D0 69467470  0073656C  6853004E  456C6C65      ptFiles.N.ShellE
0137:004074E0 75636578  00416574  4C454853  2E32334C      xecuteA.SHELL32.
.... omissis ....

come vedete e' possibile rintracciare anche a runtime le strutture che compongono 
la import table.. ovviamente nel dump precedente sono ancora presenti tutti gli
IMAGE_IMPORTS_DESCRIPTORs, IMAGE_IMPORT_BY_NAME,ecc... sapere quindi nomi e il
numero dei moduli importati e' piu' facile.. ma facciamo finta che non ci siano e 
prendiamo in considerazione solo i vari FirstThunk: l'address di GetCommandLineA
si trova ovviamente all'interno di quello relativo a kernel32..  scorrendo in
avanti e poi indietro l'array fino ad incontrare i terminatori ed utilizzando
il comando UNASSEMBLE di sIce possiamo determinare i nomi (a patto che siano
caricati i simboli relativi of coz :P) di tutte le funzioni..non ci resta quindi 
che applicare pazientemente lo stesso principio per ogni FirstThunk ed avremo tutte
le informazioni di cui abbiamo bisogno. Ora, a seconda del grado di distruzione della
IT originale il nostro lavoro spaziera' dalla "semplice" rigenerazione degli elementi
costitutivi dei FirsThunk fixati (che vi ricordo devono contenere gli RVA ai
corrispondenti IMAGE_IMPORT_BY_NAME oppure gli ordinals: exp. 407348 = BFF89F65 <=>
.idata RVA 0x7000 + ofs "BC 00 GetCommandLineA" 0x528 =  0x7528) alla creazione 
ex novo di tutti gli elementi della IT. Se state pensando che tutto questo e' un lavoro
lungo,palloso ed infame... beh avete pienamente ragione =) .. tuttavia come vi ho 
anticipato esiste MKPE che applica lo stesso metodo da noi usato manualmente per 
ricostruire la IT: quello che dobbiamo fornirgli e' solo l'elenco dei moduli utilizzati
dal processo (ottenibile anche con l'utility ModList inclusa) e un dump dell'immagine
del file .. poi lui cerchera' la IAT, processera' i vari FirstThunk trovando i moduli
che esportano quelle funzioni ed infine rigenerara' gli IMAGE_THUNK_DATA,ecc. della IT 
(ovviamente se ancora esistente) o ne creara' una nuova appendendola al PE:

lanciate il TARGET.exe.. eseguite :

modlist > TARGET.mod

editate il file generato in modo da lasciare solo l'output relativo ai muduli utilizzati 
da TARGET.exe e quindi utilizzate MKPE con i seguenti parametri:

mkpe -s -i2 -lTARGET.mod unpacked.exe  

se esiste una IT contenuta nell'immagine ma e' stata distrutta/cancellata 

mkpe -s -i3 -lTARGET.mod unpacked.exe  

se esiste la sola IAT e volete che venga creata una nuova IT da aggiungere al PE.

------------------------------------------------
*  RESOURCE     rva: 00008000  size: 00002CE0  *
------------------------------------------------

l'rva deriva direttamente dall'header cosi' come si presenta runtime in sIce (map32)
questo e' naturale considerando che il base address deve essere necessariamente 
corretto altrimenti le chiamate alle varie FindResource,LoadBitmap,ecc. fallirebbero..
problemi posso sorgere se i vari image_resource_data_entry sono rilocati dal 
packer/crypter come ulteriore misura antidump (potete accorgervi di questa eventualita'
utilizzando ad exp PESpy che  consente di percorre la res hierarchy a runtime ed 
osservando gli offsets) nel qual caso dovrete procedere ad una ricostruzione della 
.rsrc, eventualita' cmq remota quando complessa e laboriosa. La size e' invece pari 
alla dimensione fisicamente occupata = 0x7ce0 - 0x5000 = 0x2ce0.

------------------------------------------------
*  BASERELOC    rva: 0000BDDA  size: 0000000A  *
------------------------------------------------

il ripristino delle base relocations e' un problema controverso al pari della Import
Table. Come per quest'ultima le relocation posso essere gestite internamente dal
loader del packer senza che vi sia necessita' che l'header contenga un riferimento
corretto alla relocation directory. Tuttavia in questo caso le cose sono ancora
piu' complesse perche' i fixups sono applicati nel codice, nei dati,ecc. senza nessun
grado di indirezione (come possiamo considereare la IAT): se non ci e' possibile
reversare le funzioni che le gestiscono ed estrapolare le informazioni da queste,
una volta applicati i fixups ci troviamo di fronte a quello che possiamo definire 
"un fatto compiuto". Fortunatamente per gli eseguibili la possibilita' che sia 
necessario applicare la rilocazione e' sostanziamente nulla dato che ogni modulo 
che da origine ad un processo viene mappato nel suo virtual address space privato 
e cio' implica che nessun'altro modulo puo' trovarsi allo stesso virtual address 
della preferred imagebase. Di conseguenza il ripristino delle relocs per gli 
eseguibili non e' necessario ma opzionale tant'e' che spesso sono gli stessi
programmatori a compilare i propri eseguibili con le relocation stripped.
Tutt'altro discorso invece per i moduli caricati dinamicamente (dll,drv,ecc.):
in questo caso l'eventualita' di una collisone fra virtual address e quindi
di una rilocazione e' da considerarsi la norma piu' che l'eccezzione specie
in win9x dove esiste l'arena shared in cui vengono caricate quelle dll che sono 
condivise fra piu' processi (anche se il loader si sforza di caricarle nell'address
space privato quando puo') ma che deve essere spartita anche con MMF, PIPEs,ecc.
Se avete quindi necessita' di unpakkare una dll le cose si fanno difficili:
a parte il suddetto reverse del loader l'unica' possibilta' e' realizzare una 
difference map creata a partire da dump effettuati ad imagebase diversi 
e tentare di estrapolare gli RVAs dei possibili fixups secondo questa logica:

imagebase delta =  10000
   
dump1:   0137:00401007  FF15 48734000        CALL    [KERNEL32!GetCommandLineA]
dump2:   0137:00501007  FF15 48735000        CALL    [KERNEL32!GetCommandLineA]
                        ^^^^
                        |    |^^^^^^^
                        |    +- = 10000     -> aggiungi fixup entry :  TYPE = 3 
                        +-----  e' una call ->                         RVA  = 1009 
                        
ovviamente la cosa migliore sarebbe un programmino su misura che calcoli la diff. 
map e sappia discernere il "constesto" di ogni differenza distinguendo se il delta 
e' nella parte diplacement di una call,jmp,mov,ecc. e non garbage che si genera 
random o valori che cmq non hanno a che fare con i fixups. 
Fatte queste dovute considerazioni generali venieamo al PESentry: come gia'
visto per le imports le base relocation non sono distrutte ma solo cryptate in loco,
e per ripristinarle e' sufficente ripristinare l'RVA e la size.. a voi i calcoli =)

Bene se avete eseguito correttamente tutti i passaggi avrete finito il vostro primo
target packed .. contenti ? ;))
Sebbene PESentry non sia' certo un target difficile le nozioni che abbiamo utilizzato
sono applicabili a qualsiasi packer/crypter: anche se avremo a che fare con codice 
anti-debug, polimorfo, automodificante, ecc i principi del manual unpacking 
resteranno gli stessi quindi studiatevi bene il loader di PESentry..memorizzate i 
pattern di codice (specie quelli relativi a relocs e imports) perche' posso garantirvi
che vi aiuteranno a comprendere il funziomento di molti packers in circolazione... 
(siccome so che siete diffidenti per natura ;) trovate in allegato a questo tutorial
i dead listings dei loader di Neolite e ASPack =) ... ricordatevi che la ruota e' stata
scoperta alcune miglialia di anni fa' e nessun programmatore si sognerebbe di 
reinventarla ogni volta ;)

--==[ NOTE FINALI]==------------------------------------------------------------------

Nelle mie intenzioni questo tutorial avrebbe dovuto comprendere due ulteriori sezioni 
dedicate ai general unpackers e soprattutto a PROCDUMP e gli aspetti avanzati di questo
(scripts,Brahma server,ecc..): tuttavia in questo periodo non ho molto tempo libero 
(esami,lavoro e chi piu' ne ha piu' ne metta...);  mi sono inoltre reso conto che
stavo persevernado un'altra volta nel mio solito errore di dilagare in una esposizione
lunghissima al limite del logorroico.. per farla breve,  ho deciso di spezzare in due 
parti questo documento e di scrivere quella dedicata a ProcDump&scripts a breve, 
nonappena passata la bufera esami... almeno spero =). 
Ultima cosa :in allegato sono inclusi anche  sorgenti del PESpy un'utility dedicata 
all'analisi del PE sia filebased che a runtime ed intesa come supporto per il dumping..
Allo stadio attuale la considero una sorta di esperimento per quel che vuol essere 
(almeno nelle mie intenzioni) un dumper made in ringZ3r0 (se avete commenti o volete 
contribuire alla cosa scrivetemi pure). I sorgenti sono commentati anche se  
la funzione di detect e scan della IAT non e' ancora implementata ed e' stato testato
solo under w95c.. cmq lo sara' molto presto tempo libero permettendo =)

Concludo ringraziando velocemente Neural_Noise e GEnius che si sorbiscono le mie 
strampalate chiaccherate ,  +Malattia e Yan Orel per essere fonte continua di notizie 
e link preziosi.. tutti i membri di RingZ3r0 per essere semplicemnte unici =),  
un saluto poi a tutti i frequentatori di #Crack-it e in specie a  Kry0, MoonShadow,
T3X e xAONINO con cui tiro spesso ore assurde =)


byz Kill3xx